package de.syfy.project.game;

import de.syfy.project.engine.TextureLoader;
import de.syfy.project.engine.interfaces.World;
import de.syfy.project.engine.interfaces.Game;
import java.awt.Font;
import java.awt.geom.Point2D;
import java.util.List;
import static org.lwjgl.opengl.GL11.*;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.newdawn.slick.Color;
import org.newdawn.slick.TrueTypeFont;

/**
 *
 * @author Timo
 * 
 * GamePanel soll die anzuzeigende Oberfläche darstellen. 
 * 
 * Wird noch erweitert um das Bewegen in einer "Welt" zu simulieren!
 */
public class GamePanel implements Game{
    public static String WINDOW_TITLE = "GameEngine";
    public static TextureLoader textureLoader;
    
    private static long timerTicksPerSecond = Sys.getTimerResolution();
    
    private long delta = 0;
    private long lastT = 0;
    private long fps = 0;
    private boolean showInfo = true;
    private boolean gameRunning = true;
    
    public int DISPLAY_WIDTH = 800;
    public int DISPLAY_HEIGHT = 600;
    public int SCROLL_SPEED = 15;
    private int mouse_x;
    private int mouse_y;
    
    private static Game gameInstance;
    private World actualWorld;
    private List<World> worlds;
    private TrueTypeFont font;
    private Color infoColor = Color.cyan;
    
    
    public GamePanel(){
        initialize();
    }
    
    private void initialize(){
        //Nur zum Testen!
        actualWorld = new GameWorld(this,1000,1000,new Point2D.Float(100,100));
        Display.setTitle(WINDOW_TITLE);
        try {       
            Display.setDisplayMode(new DisplayMode(DISPLAY_WIDTH,DISPLAY_HEIGHT));
            Display.setFullscreen(false);
            Display.create();
            Mouse.create();
            Keyboard.create();
            initGL();
            Font awtFont = new Font("Arial", Font.PLAIN, 14);
            font = new TrueTypeFont(awtFont,true);
            gameInstance = this;
        } catch (LWJGLException ex) {
            //Logger
            System.out.println("Beende Spiel:");
            ex.printStackTrace();
            return;
        }
    }
    
    private void initGL(){
        //2D Initialization
        glEnable(GL_TEXTURE_2D);      
        glDisable(GL_DEPTH_TEST);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0, 1, -1);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glViewport(0,0,DISPLAY_WIDTH,DISPLAY_HEIGHT);
        textureLoader = new TextureLoader();                          
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    }
    
    
    public void calculateDelta(){
        delta = getTime() - lastT;
        lastT = getTime();
        fps = (long)(1000.0/delta+0.5);
    }
    
    public void calculateMousePosition(){
        mouse_x = Mouse.getX();
        mouse_y = DISPLAY_HEIGHT-Mouse.getY();
    }
    
    public static long getTime(){
        return (Sys.getTime() * 1000) / timerTicksPerSecond;
    }
    
    @Override
    public World getActualWorld(){
        return actualWorld;
    }
    
    @Override
    public Point2D.Float worldPointToUIPoint(Point2D.Float p){
        float dif_x = p.x- actualWorld.getActualCoordinate().x;
        float dif_y = p.y - actualWorld.getActualCoordinate().y;
        return new Point2D.Float(DISPLAY_WIDTH/2+dif_x,DISPLAY_HEIGHT/2+dif_y);
    }
    
    @Override
    public Point2D.Float uiPointToWorldPoint(Point2D.Float p){
        float dif_x = DISPLAY_WIDTH/2 - p.x;
        float dif_y = DISPLAY_HEIGHT/2 - p.y;
        return new Point2D.Float(actualWorld.getActualCoordinate().x-dif_x,actualWorld.getActualCoordinate().y-dif_y);        
    }
    
    /*
     * Color aus Slick-Util nicht AWT-Color
     */
    public void drawString(String text, float x, float y, Color c){
        glEnable(GL_TEXTURE_2D);
        org.newdawn.slick.opengl.TextureImpl.bindNone();
        font.drawString(x, y, text,c);
        glDisable(GL_TEXTURE_2D);
    }
    
    @Override
    public void gameLoop() {
        while (gameRunning) {
            Display.sync(60);
            calculateDelta();
            calculateMousePosition();
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            render();
            if(showInfo)renderInfo();
            checkKeyboard();
            if (Display.isCloseRequested()) {
                gameRunning = false;
            }
            Display.update();
        }
        Display.destroy();
        Mouse.destroy();
        Keyboard.destroy();
    }
    
    public void start(){        
        gameLoop();      
    }

    public void render() {
        actualWorld.drawWorld();
        if(showInfo){                    
            actualWorld.drawGrid();
        }
        actualWorld.drawSprites(delta);
        
    }
    
    public void renderInfo(){
        org.newdawn.slick.opengl.TextureImpl.bindNone(); //Workaround, wir lösen die aktuelle Textur, damit der Text vernünftig gerendert werden kann
        font.drawString(DISPLAY_WIDTH-115, 15, "FPS: "+fps, infoColor);
        if(Mouse.isInsideWindow()){
            Point2D.Float p = uiPointToWorldPoint(new Point2D.Float(mouse_x,mouse_y));
            font.drawString(DISPLAY_WIDTH-115, 30, "Maus-UI-X:"+mouse_x,infoColor);
            font.drawString(DISPLAY_WIDTH-115, 45, "Maus-UI-Y:"+mouse_y,infoColor);
            font.drawString(DISPLAY_WIDTH-115, 60, "Maus-Welt-X:"+p.x,infoColor);
            font.drawString(DISPLAY_WIDTH-115, 75, "Maus-Welt-Y:"+p.y,infoColor);
        }else{
            font.drawString(DISPLAY_WIDTH-115, 30, "Maus-UI-X: null",infoColor);
            font.drawString(DISPLAY_WIDTH-115, 45, "Maus-UI-Y: null",infoColor);
            font.drawString(DISPLAY_WIDTH-115, 60, "Maus-Welt-X: null",infoColor);
            font.drawString(DISPLAY_WIDTH-115, 75, "Maus-Welt-Y: null",infoColor);
        }
    }
    
    public void checkKeyboard() {
        /*
         * Hier habe ich zur Zeit zum Testen die Bildschirmbewegung implimentiert!
         */
        if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) {
            Point2D.Float p = new Point2D.Float(actualWorld.getActualCoordinate().x + SCROLL_SPEED, actualWorld.getActualCoordinate().y);
            actualWorld.setActualCoordinate(p);
        }
        if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) {
            Point2D.Float p = new Point2D.Float(actualWorld.getActualCoordinate().x - SCROLL_SPEED, actualWorld.getActualCoordinate().y);
            actualWorld.setActualCoordinate(p);
        }
        if (Keyboard.isKeyDown(Keyboard.KEY_UP)) {
            Point2D.Float p = new Point2D.Float(actualWorld.getActualCoordinate().x, actualWorld.getActualCoordinate().y - SCROLL_SPEED);
            actualWorld.setActualCoordinate(p);
        }
        if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) {
            Point2D.Float p = new Point2D.Float(actualWorld.getActualCoordinate().x, actualWorld.getActualCoordinate().y + SCROLL_SPEED);
            actualWorld.setActualCoordinate(p);
        }
    }

    @Override
    public boolean isGameRunning() {
        return gameRunning;
    }

    @Override
    public TextureLoader getTextureLoader() {
        return textureLoader;
    }
    
    public static Game getGameInstance(){
        return gameInstance;
    }
}
